To introduce the new Service Broker constructs you’ll be using, Figure 1 shows the interrelations between the constructs described in the upcoming subsections.
Figure 1
illustrates the fact that a dialog is a conversation between two
services. These services exchange typed (or untyped) messages by sending
them to queues according to the rules of a contract. Each service can
have a service program activated by Service Broker to receive messages
from a queue. Every conversation belongs to a conversation group.
Messages are always sent with respect to a conversation group. One or
more conversation groups make up a Service Broker application.
Defining Messages and Choosing a Message Type
For the AdventureWorks2008 database to communicate with the XCatMgmt
database via Service Broker, a dialog between two services must take
place. Within this conversation, each service sends messages to or
receives messages from queues, providing the indirection needed for the
underlying systems to stay loosely coupled.
The dialog messages are typed to constrain and (optionally) validate their content. You use the new SQL Server database object MESSAGE
to represent a typed message. Defining the messages to be transmitted
is the first step in building a Service Broker application.
You create SQL Server messages by using the following syntax:
CREATE MESSAGE TYPE [ AUTHORIZATION UserName ]
[ VALIDATION = {
NONE | EMPTY | WELL_FORMED_XML |
VALID_XML WITH SCHEMA COLLECTION XMLSchemaCollectionName
} ]
You can alter message types by using the intuitive ALTER MESSAGE TYPE
syntax. Before you create the first message type, you need to create a
Windows user on the local server and associate a SQL Server login with
it, giving it db_owner permissions in both AdventureWorks2008 and XCatMgmt. You need to specify this user in the AUTHORIZATION clause of any object you create that includes this clause. In the examples in this article, this is exemplified as SSBTestUserName.
Messages can be validated based on the following options:
NONE— Do no validation; any message content is acceptable.
EMPTY— Transmitted messages must be empty.
WELL_FORMED_XML— Transmitted messages must be any well-formed XML.
VALID_XML WITH SCHEMA COLLECTION— Transmitted messages must be valid XML corresponding to any schema in the XML schema collection specified in XMLSchemaCollectionName.
It is highly recommended that applications use either WELL_FORMED_XML or VALID_XML WITH SCHEMA COLLECTION.
You don’t want just any old message structure coming across the pipe
because your application will almost certainly be looking for specific
values in a specific location. XML is appropriate because it is the
ubiquitous standard today. Note that the XML content of messages is
actually stored as varbinary(MAX).
Now you should go ahead and create your two message types, both of which should be set to VALID_XML.
The first deals with catalog entries and/or changes (that is, updates
and deletions), and the second is a generic message type you use for all
acknowledgments. Listing 49.2 shows the schemas for these message types, along with the necessary schema collection and message type creation syntax.
Listing 1. DDL for Creating the Sample Message Types and Their Associated XML Schema Collections
-- Note: -- Execute the T-SQL below, and then change the USE statement -- to 'USE AdventureWorks2008' and execute it again. USE XCatMgmt GO CREATE XML SCHEMA COLLECTION CatalogChangeSchema AS '<?xml version="1.0"?> <xs:schema targetNamespace="urn:www-samspublishing-com:examples:ssb:catalogchange" elementFormDefault="qualified" xmlns="urn:www-samspublishing-com:examples:ssb:catalogchange" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="CatalogChangeMessage"> <xs:complexType> <xs:sequence maxOccurs="unbounded"> <xs:element name="CatalogChange" type="CatalogChangeType"/> </xs:sequence> </xs:complexType> </xs:element>
<xs:complexType name="CatalogChangeType"> <xs:sequence> <xs:element name="Summary" type="xs:string"/> <xs:element name="Features" type="xs:string" minOccurs="0"/> <xs:element name="Specifications" type="xs:string" minOccurs="0"/> </xs:sequence> <xs:attribute name="SourceProductId" type="xs:integer" use="required"/> <xs:attribute name="ManufacturerId" type="xs:integer" use="required"/> <xs:attribute name="ChangeType"> <xs:simpleType> <xs:restriction base="xs:integer"> <xs:enumeration id="Insert" value="1"/> <xs:enumeration id="Update" value="2"/> <xs:enumeration id="Delete" value="3"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="Price" type="xs:decimal"/> <xs:attribute name="Name" type="xs:string"/> </xs:complexType> </xs:schema>' GO CREATE MESSAGE TYPE [//samspublishing.com/SS2008/SSB/MessageTypes/CatalogChangeMessage] AUTHORIZATION [SSBTestUserName] VALIDATION = VALID_XML WITH SCHEMA COLLECTION CatalogChangeSchema GO CREATE XML SCHEMA COLLECTION GenericAcknowledgementSchema AS '<?xml version="1.0" encoding="utf-8" ?> <xs:schema targetNamespace="urn:www-samspublishing-com:examples:ssb:genericack" elementFormDefault="qualified" xmlns="urn:www-samspublishing-com:examples:ssb:genericack" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="MsgTypeType"> <xs:restriction base="xs:integer"> <xs:enumeration id="SuccessMsg" value="0"/> <xs:enumeration id="FailureMsg" value="1"/> <xs:enumeration id="WarningMsg" value="2"/> </xs:restriction> </xs:simpleType>
<xs:element name="Ack"> <xs:complexType> <xs:sequence> <xs:element name="ResultMessage"> <xs:complexType mixed="true"> <xs:attribute name="ContentId" type="xs:integer" use="optional"/> <xs:attribute name="MsgType" type="MsgTypeType"/> </xs:complexType> </xs:element> </xs:sequence> <xs:attribute name="ResultCode"> <xs:simpleType> <xs:restriction base="xs:integer"> <xs:enumeration id="Success" value="1"/> <xs:enumeration id="Failure" value="0"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element> </xs:schema>' GO CREATE MESSAGE TYPE
[//samspublishing.com/SS2008/SSB/MessageTypes/GenericAck] AUTHORIZATION [SSBTestUserName] VALIDATION = VALID_XML WITH SCHEMA COLLECTION GenericAcknowledgementSchema
|
Note that the message types and schema collections should be created (as the Listing 1 comment indicates) in both participating databases, AdventureWorks2008XCatMgmt. and
The reason is that when you create the XML messages, you might want to
temporarily store them as local typed XML variables to ensure that they
are validated before being sent. However, it is only necessary to create
the schema collections on the database where the message will be
received because the receiving instance of Service Broker performs the
validation.
In the MESSAGE TYPE DDL, you should use this standard naming convention for Service Broker objects: //DomainName/Path/ObjectType/ObjectName.
This convention will help you identify your objects later. (Don’t worry
if the name is long; you can use Object Explorer’s drag-and-drop
feature to drag the name into your scripts.) If you’re curious, you can
view the newly created objects in Object Explorer by selecting the Service Broker node and then expanding the Message Types node. You can find the XML schema collections by selecting the Programmability node and then selecting the Types node and expanding the XML Schema Collections node.
Note that there are
several built-in message types that any queue can receive from Service
Broker. Service programs should be built to handle these as well as the
specific message types defined in their contracts. You can view them all
in the Object Brower (they all begin with http://schemas.microsoft.com/SQL/ServiceBroker/). When receiving messages from a queue, you should filter them based on the message_type_name column of the queue to be sure you handle each one correctly. You can expect to see these types in your queues:
Error—
This type is enqueued by Service Broker whenever an error is
encountered. Alternatively, a user program can choose to create these
types.
EndDialog— This type is enqueued by Service Broker when a conversation ends in response to calls to END CONVERSATION .
Service programs can also send messages of the built-in type DialogTimer.
Service Broker delivers these messages to the specified queue when a
specific time period has elapsed. To tell Service Broker to send a DialogTimer
message to the queue associated with a service after 5 minutes has
elapsed, for example, you execute the following T-SQL during a
conversation in the service program:
BEGIN CONVERSATION TIMER (@ConversationHandle) TIMEOUT = 600
In this code, you replace @ConversationHandle with the unique identifier assigned to your conversation.
Now that all your message
types are in place and you know which built-in messages to expect, you
can create the contract that defines the message flow in this system.